from sqlalchemy import and_, select
from sqlalchemy.exc import DBAPIError, IntegrityError

from src.core.exceptions.common import RepoError
from src.core.exceptions.order import OrderIdAlreadyExist
from src.core.exceptions.product import (
    ProductEmailAlreadyExist,
    ProductLoginAlreadyExist,
)
from src.database.exception_mapper import exception_mapper
from src.database.models import Product
from src.database.repositories.base import SQLAlchemyRepo


class ProductRepoImpl(SQLAlchemyRepo):
    @exception_mapper
    async def get_available_products(
        self, category_id: int, limit: int | None = None
    ) -> list[Product]:
        """Получаем доступные товары"""

        query = select(Product).where(
            and_(
                Product.order_id == None,
                Product.category_id == category_id,
            )
        )

        if limit:
            query = query.limit(limit)

        res = await self._session.scalars(query)

        products: list[Product] = list(res)

        return products

    @exception_mapper
    async def create_product(self, product: Product) -> None:
        """Создаем товар"""

        self._session.add(product)
        try:
            await self._session.flush((product,))
        except IntegrityError as err:
            self._parse_error(err)

    @exception_mapper
    async def update_product(self, product: Product) -> None:
        """Обновляем товар"""

        try:
            await self._session.merge(product)
        except IntegrityError as err:
            self._parse_error(err)

    @staticmethod
    def _parse_error(err: DBAPIError) -> None:
        error_msg = err.__cause__.args[1]
        if "uq_product_email" in error_msg:
            raise ProductEmailAlreadyExist from err
        elif "uq_product_login" in error_msg:
            raise ProductLoginAlreadyExist from err
        else:
            raise RepoError from err
